package parser

import (
	"errors"
	"reflect"
	"sort"
	"strings"
)

type cacheKeyString string

func newCacheKeyString(tableFieldNames, selectField, omitField []string) cacheKeyString {
	return cacheKeyString(strings.Join(append(append(tableFieldNames, selectField...), omitField...), ","))
}

type cacheValue struct {
	result []string
	hit    bool
}

var cache = make(map[cacheKeyString]cacheValue)

func GetField(tableFieldNames, selectField, omitField []string) []string {
	// 先尝试从缓存中获取结果
	key := newCacheKeyString(tableFieldNames, selectField, omitField)
	if cacheValue, ok := cache[key]; ok {
		cacheValue.hit = true // 命中标记设为 true
		return cacheValue.result

	}
	// 如果selectField有值，则直接返回selectField
	if len(selectField) > 0 {
		result := make([]string, len(selectField))
		copy(result, selectField)
		// 将结果存入缓存中
		cache[key] = cacheValue{result, false}
		return result
	}
	// 如果selectField和omitField都没有值，则返回tableFieldNames
	if len(selectField) == 0 && len(omitField) == 0 {
		result := make([]string, len(tableFieldNames))
		copy(result, tableFieldNames)
		// 将结果存入缓存中
		cache[key] = cacheValue{result, false}
		return result
	}
	// 如果omitField有值，则从tableFieldNames中移除omitField包含的字段后返回结果
	result := make([]string, 0, len(tableFieldNames))
	for _, field := range tableFieldNames {
		if !contains(omitField, field) {
			result = append(result, field)
		}
	}
	// 将结果存入缓存中
	cache[key] = cacheValue{result, false}
	return result
}

func contains(strs []string, str string) bool {
	sort.Strings(strs) // 必须先将数组排序
	index := sort.SearchStrings(strs, str)
	return index < len(strs) && strs[index] == str
}

// 判断传入的参数是不是 切片[]MyStruct{},此处带入的是指针
func IsSlice(v interface{}) bool {
	value := reflect.ValueOf(v)
	if value.Kind() != reflect.Ptr || value.IsNil() {
		return false
	}
	elem := value.Elem()
	return elem.Kind() == reflect.Slice
}

// 获取表名和分表信息
func GetTableNameAndSubTableField(model interface{}) (string, bool, error) {
	isSlice := IsSlice(model)
	if isSlice {
		tableName := getTableNameWithSlice(model)
		if tableName == "" {
			return "", false, errors.New("get table name error")
		}
		//subTableFile := getSubTableFieldWithSlice(model)
		return tableName, true, nil
	} else {
		tableName := getTableName(model)
		if tableName == "" {
			return "", false, errors.New("get table name error")
		}
		//subTableFile := getSubTableFile(model)
		return tableName, false, nil
	}
}

var tableNameCache = make(map[reflect.Type]string)

// 获取slice struct 中的tableName
func getTableNameWithSlice(model interface{}) string {
	// 获取切片的值信息
	v := reflect.ValueOf(model).Elem()

	// 获取切片中第一个元素的类型
	elemType := v.Type().Elem()
	if tableName, ok := tableNameCache[elemType]; ok {
		return tableName
	}

	// 获取元素的值信息
	elem, ok := reflect.New(elemType).Interface().(GetTableNamer)
	if !ok {
		return ""
	}

	tableName := elem.GetTableName()
	// 缓存结果
	tableNameCache[elemType] = tableName

	return tableName
}

// 获取表名
type GetTableNamer interface {
	GetTableName() string
}

func getSubTableFieldWithSlice(model interface{}) string {
	// 获取切片的值信息
	v := reflect.ValueOf(model).Elem()
	// 遍历切片中的每个元素
	for i := 0; i < v.Len(); i++ {
		// 获取元素的值信息
		if elem, ok := v.Index(i).Addr().Interface().(GetSubTableFielder); ok {
			// 调用GetTableName方法
			return elem.GetSubTableField()
		}

	}
	return ""
}

type GetSubTableFielder interface {
	GetSubTableField() string
}

// 获取表名
func getTableName(model interface{}) string {
	if v, ok := model.(interface{ GetTableName() string }); ok {
		return v.GetTableName()
	}
	return ""
}

// 获取分表信息
func getSubTableFile(model interface{}) string {
	if v, ok := model.(interface{ GetSubTableField() string }); ok {
		return v.GetSubTableField()
	}
	return ""
}

func GetValueTag(val reflect.Value, model interface{}, fieldName string) interface{} {
	//val := reflect.ValueOf(model).Elem()
	typeOfT := val.Type()

	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		tag := typeOfT.Field(i).Tag.Get("column")
		if tag == fieldName {
			return field.Interface()
		}
	}
	return nil
}

func addQuotes(caseSensitive bool, strs []string) []string {
	if !caseSensitive {
		return strs
	}

	var result []string
	for _, str := range strs {
		quotedStr := "\"" + str + "\""
		result = append(result, quotedStr)
	}
	return result
}
